package com.weixing.mall.redis;

import org.springframework.aop.support.AopUtils;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * 自定义缓存Key生成策略
 *
 * @Author: kfc
 * @Description: <br/>
 * Date:Create in 2019/9/12 9:33
 * @Modified By:
 */
public class CustomKeyGenerator implements KeyGenerator {

    public CustomKeyGenerator() {
    }

    @Override
    public Object generate(Object target, Method method, Object... params) {
        return generateKey(target, method, params);
    }


    private Object generateKey(Object target, Method method, Object... params) {
        String className = AopUtils.isAopProxy(target) ? AopUtils.getTargetClass(target).getSimpleName() : target.getClass().getSimpleName();
        String methodName = method.getName();
        if (params.length == 0) {
            params = CustomKey.EMPTY_PARAMS;
        }
        return new CustomKey(className, methodName, params);
    }

    /**
     * Like {@link org.springframework.cache.interceptor.SimpleKey} but considers the method.
     */
    static final class CustomKey {
        public static final Object[] EMPTY_PARAMS = new Object[0];
        private final String className;
        private final String methodName;
        private final Object[] params;
        private final int hashCode;

        /**
         * Initialize a key.
         *
         * @param className      the receiver class
         * @param methodName the method name
         * @param params     the method parameters
         */
        CustomKey(String className, String methodName, Object[] params) {
            this.className = className;
            this.methodName = methodName;
            this.params = params;
            int code = Arrays.deepHashCode(params);
            code = 31 * code + className.hashCode();
            code = 31 * code + methodName.hashCode();
            this.hashCode = code;
        }

        @Override
        public int hashCode() {
            return this.hashCode;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (!(obj instanceof CustomKey)) {
                return false;
            }
            CustomKey other = (CustomKey) obj;
            if (this.hashCode != other.hashCode) {
                return false;
            }

            return this.className.equals(other.className)
                    && this.methodName.equals(other.methodName)
                    && Arrays.deepEquals(this.params, other.params);
        }

        @Override
        public String toString() {
            return className + "&" + methodName + " [" + StringUtils.arrayToCommaDelimitedString(this.params) + "]";
        }

    }

}
